package com.ehuoyun.ecstore;

import java.io.File;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import net.sourceforge.stripes.config.Configuration;
import net.sourceforge.stripes.controller.FileUploadLimitExceededException;
import net.sourceforge.stripes.controller.multipart.DefaultMultipartWrapperFactory;
import net.sourceforge.stripes.controller.multipart.MultipartWrapper;
import net.sourceforge.stripes.controller.multipart.MultipartWrapperFactory;
import net.sourceforge.stripes.exception.StripesRuntimeException;
import net.sourceforge.stripes.util.Log;


public class GAEMultipartWrapperFactory implements MultipartWrapperFactory {

    /** The configuration key used to lookup the implementation of MultipartWrapper. */
    public static final String WRAPPER_CLASS_NAME = "MultipartWrapper.Class";

    /** The names of the MultipartWrapper classes that will be tried if no other is specified. */
    public static final String[] BUNDLED_IMPLEMENTATIONS = {
            "net.sourceforge.stripes.controller.multipart.CommonsMultipartWrapper",
            "net.sourceforge.stripes.controller.multipart.CosMultipartWrapper" };

    /** Key used to lookup the name of the maximum post size. */
    public static final String MAX_POST = "FileUpload.MaximumPostSize";

    private static final Log log = Log.getInstance(DefaultMultipartWrapperFactory.class);

    // Instance level fields
    private Class<? extends MultipartWrapper> multipartClass;
    private long maxPostSizeInBytes = 1024 * 1024 * 10; // Defaults to 10MB
    private File temporaryDirectory;

    /**
     * Invoked directly after instantiation to allow the configured component to perform one time
     * initialization.  Components are expected to fail loudly if they are not going to be in a
     * valid state after initialization.
     *
     * @param config the Configuration object being used by Stripes
     * @throws Exception should be thrown if the component cannot be configured well enough to use.
     */
    @SuppressWarnings("unchecked")
	public void init(Configuration config) throws Exception {
    	// always use GAEMultipartWrapper.
    	String className = "com.ehuoyun.ecstore.GAEMultipartWrapper";
        try {
            this.multipartClass = ((Class<? extends MultipartWrapper>) Class
                    .forName(className));
        }
        catch (Throwable t) {
            log.debug(getClass().getSimpleName(), " not using ", className,
                    " because it failed to load. This likely means the supporting ",
                    "file upload library is not present on the classpath.");
        }

        // Log the name of the class we'll be using or a warning if none could be loaded
        if (this.multipartClass == null) {
            log.warn("No ", MultipartWrapper.class.getSimpleName(),
                    " implementation could be loaded");
        }
        else {
            log.info("Using ", this.multipartClass.getName(), " as ", MultipartWrapper.class
                    .getSimpleName(), " implementation.");
        }

        // always pass null to GAEMultipartWrapper
        this.temporaryDirectory = null;

        // See if a maximum post size was configured
        String limit = config.getBootstrapPropertyResolver().getProperty(MAX_POST);
        if (limit != null) {
            Pattern pattern = Pattern.compile("([\\d,]+)([kKmMgG]?).*");
            Matcher matcher = pattern.matcher(limit);
            if (!matcher.matches()) {
                log.error("Did not understand value of configuration parameter ", MAX_POST,
                         " You supplied: ", limit, ". Valid values are any string of numbers ",
                         "optionally followed by (case insensitive) [k|kb|m|mb|g|gb]. ",
                         "Default value of ", this.maxPostSizeInBytes, " bytes will be used instead.");
            }
            else {
                String digits = matcher.group(1);
                String suffix = matcher.group(2).toLowerCase();
                int number = Integer.parseInt(digits);

                if ("k".equals(suffix)) { number = number * 1024; }
                else if ("m".equals(suffix)) {  number = number * 1024 * 1024; }
                else if ("g".equals(suffix)) { number = number * 1024 * 1024 * 1024; }

                this.maxPostSizeInBytes = number;
                log.info("Configured file upload post size limit: ", number, " bytes.");
            }
        }
    }

    /**
     * Wraps the request in an appropriate implementation of MultipartWrapper that is capable of
     * providing access to request parameters and any file parts contained within the request.
     *
     * @param request an active HttpServletRequest
     * @return an implementation of the appropriate wrapper
     * @throws IOException if encountered when consuming the contents of the request
     * @throws FileUploadLimitExceededException if the post size of the request exceeds any
     *          configured limits
     */
    public MultipartWrapper wrap(HttpServletRequest request) throws IOException, FileUploadLimitExceededException {
        try {
            MultipartWrapper wrapper = this.multipartClass.newInstance();
            wrapper.build(request, this.temporaryDirectory, this.maxPostSizeInBytes);
            return wrapper;
        }
        catch (IOException ioe) { throw ioe; }
        catch (FileUploadLimitExceededException fulee) { throw fulee; }
        catch (Exception e) {
            throw new StripesRuntimeException
                    ("Could not construct a MultipartWrapper for the current request.", e);
        }
    }

}
